package es.uned.etsii.si3.taller.servlets;

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.Interval;

import com.j256.ormlite.stmt.QueryBuilder;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;

import es.uned.etsii.si3.taller.Empleado;
import es.uned.etsii.si3.taller.Empleado.Categoria;
import es.uned.etsii.si3.taller.FactoriaDAO;
import es.uned.etsii.si3.taller.FactoriaFunciones;
import es.uned.etsii.si3.taller.Trabajo;
import es.uned.etsii.si3.taller.misc.IteradorTemporalInverso;
import es.uned.etsii.si3.taller.misc.ProporcionaFuncionalidad;

public class CargaDeTrabajo extends ActionSupport implements Preparable {
	private static final long serialVersionUID = 1L;
	private static final SimpleDateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd");
	private static final int numeroSemanas = 10;
	private static final int numeroMeses   = 5;
	
	private List<Empleado> listaMecanicos = null;
	private int idMecanico = 0;
	private Empleado mecanico = null;
	private int periodo = 0;
	private List<Carga> listaCarga = null;
	private String tratamiento = null;
	
	public class Carga {
		private int carga;
		private String fechaInicio;
		private String fechaFin;
		
		public int getCarga() {
			return carga; 
		}
		
		public String getFechaInicio() {
			return fechaInicio;
		}
		
		public String getFechaFin() {
			return fechaFin;
		}
		
		public void setCarga(int c) {
			carga = c;
		}
		
		public void setFechaInicio(String fI) {
			fechaInicio = fI;
		}
		
		public void setFechaFin(String fF) {
			fechaFin = fF;
		}
	}
	
	/* BEGIN: getters y setters */
	
	public int getPeriodo() {
		return periodo;
	}
	
	public void setPeriodo(int p) {
		periodo = p;
	}
	
	public List<Carga> getListaCarga() {
		return listaCarga;
	}
	
	public List<Empleado> getListaMecanicos() {
		return listaMecanicos;
	}
	
	private void setListaMecanicos(List<Empleado> nuevaLista) {
		listaMecanicos = nuevaLista;
	}
	
	public int getIdMecanico() {
		if (mecanico == null)
			return 0;
		
		return mecanico.getId();
	}

	public void setIdMecanico(int id) {
		idMecanico = id;
	}
	
	public Empleado getMecanico() {
		return mecanico;
	}
	
	public String getTratamiento() {
		return tratamiento;
	}

	/* END: getters y setters */

	/**
	 * Valida los datos introducidos en el formulario
	 * 
	 */
	@Override
	public void validate() {
		if (idMecanico != 0) {
			try {
				mecanico = FactoriaDAO.recuperar(Empleado.class, idMecanico);
				if (mecanico == null)
					addFieldError("idTaller", "Se ha escogido un valor que no aparece en el desplegable");
				
			} catch (SQLException e) {
				addFieldError("idTaller", "Error al intentar recuperar el mecánico de la base de datos: " + e.toString());
			}
		}
	}

	/**
	 * Obtiene la lista de mecánicos del taller
	 */
	@Override
	public void prepare() {
		try {
			QueryBuilder<Empleado, Integer> mecanicosQb = FactoriaDAO.getQueryBuilder(Empleado.class);
			mecanicosQb.where().eq(Empleado.CATEGORIA_FIELD_NAME, Categoria.MECANICO);
			mecanicosQb.orderBy(Empleado.APELLIDOS_FIELD_NAME, true);
			
			setListaMecanicos(mecanicosQb.query());
		} catch (SQLException e) {
			addActionError("Se produjo un error intentando recuperar la lista de mecánicos" + e.toString());
		}
				
	}
	
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_VER_CARGA_DE_TRABAJO)
	public String display() {
		return NONE;
	}
	
	private String darFormatoFecha(DateTime t) {
		return String.format("%s", formatoFecha.format(t.toDate()));
	}
	
	private String darFormatoFechaSql(DateTime t) {
		return String.format("DATE '%s'", formatoFecha.format(t.toDate()));
	}

	/**
	 * Muestra la carga de trabajo de los mecánicos
	 */
	@ProporcionaFuncionalidad(identificador = FactoriaFunciones.ADMIN_VER_CARGA_DE_TRABAJO)
	public String execute() {
		listaCarga = new ArrayList<Carga>();

		try {
			QueryBuilder<Trabajo, Integer> trabajoQb = FactoriaDAO.getQueryBuilder(Trabajo.class);
			
			IteradorTemporalInverso it;
			if (getPeriodo() == 0) {
				it = new IteradorTemporalInverso(new DateTime(), numeroSemanas, true);
				tratamiento = String.format("las últimas %d semanas", numeroSemanas);
			}
			else {
				it = new IteradorTemporalInverso(new DateTime(), numeroMeses, false);
				tratamiento = String.format("los últimos %d meses", numeroMeses);
			}
			
			for (Interval intervalo: it) {
				DateTime fechaInicio = intervalo.getStart();
				DateTime fechaFin    = intervalo.getEnd().minusMillis(1);
				trabajoQb.clear();
				trabajoQb.selectRaw("SUM(\"TRABAJO\".\"horas\")");
				
				trabajoQb.where().eq(Trabajo.ID_USUARIO_FIELD_NAME, mecanico.getUsuario())
								 .and()
								 .raw(String.format("\"%s\" BETWEEN %s AND %s",
										 			Trabajo.FECHARECEPCION_FIELD_NAME,
										 			darFormatoFechaSql(fechaInicio),
										 			darFormatoFechaSql(fechaFin)));

				String query = trabajoQb.prepareStatementString();
				String[] resultados = FactoriaDAO.getDao(Trabajo.class).queryRaw(query).getFirstResult();
				Integer horas;
				if ((resultados == null) || (resultados[0] == null)) {
					horas = new Integer(0);
				}
				else {
					horas = new Integer(resultados[0]);
				}
				
				Carga nuevaCarga = new Carga();
				nuevaCarga.setCarga(horas);
				nuevaCarga.setFechaInicio(darFormatoFecha(fechaInicio));
				nuevaCarga.setFechaFin(darFormatoFecha(fechaFin));
				
				listaCarga.add(nuevaCarga);
				
				trabajoQb.clear();
				trabajoQb.where().eq(Trabajo.ID_USUARIO_FIELD_NAME, mecanico.getUsuario())
								 .and()
								 .raw(String.format("\"%s\" BETWEEN %s AND %s",
										 			Trabajo.FECHARECEPCION_FIELD_NAME,
										 			darFormatoFechaSql(fechaInicio),
										 			darFormatoFechaSql(fechaFin)));
				
			}
		} catch (SQLException e) {
			addActionError("Error al intentar obtener la carga: " + e.toString());
		}
		
		if (hasActionErrors())
			return ERROR;
		
		return SUCCESS;
	}
}